package cmd

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/chromedp"
	// "github.com/chromedp/chromedp/device"
)

type ReviewCrawlInfo struct {
	ShopID      string   `json:"shop_id"`
	Cnt         int      `json:"cnt"`
	From        string   `json:"from"`
	To          string   `json:"to"`
	ReviewItems []string `json:"review_items,omitempty"`
}

func (tr *TaskRunner) ValidateShop(shopID string) *TaskRunner {
	refererUrl := fmt.Sprintf("%s/shop/%s", dpHost, shopID)
	reviewUrl := fmt.Sprintf("%s/shop/%s/review_all?queryType=sortType&&queryVal=latest", dpHost, shopID)
	// ?queryType=sortType&&queryVal=latest 时间倒序
	const selReviewCount = `#review-list > div.review-list-container > div.review-list-main > div.review-tabs.clearfix > div.tabs > ul > li > span > em`
	tr.NavigateWithReferer(reviewUrl, refererUrl)
	tr.tasks = append(tr.tasks, chromedp.Tasks{
		IfPresent(
			selReviewCount, Sequence(
				IfHasText(selReviewCount, chromedp.Tasks{}),
			),
		),
	})
	return tr
}

func (tr *TaskRunner) FetchReviewsSinceOld(shopID string, latestDays int) *TaskRunner {
	const selReviewWords = `#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items > ul > li > div > div.review-words`
	const selReviewWordItemTpl = `#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items > ul > li:nth-child(%d) > div > div.review-words`
	extracts := []string{}
	cutoffDate := time.Now().AddDate(0, 0, -latestDays)
	tr.tasks = append(tr.tasks, chromedp.Tasks{
		// chromedp.Emulate(device.IPhone12Pro),

		Iter(
			selReviewWords,
			IterNodeNextFunc(func(ctx context.Context, idx int, node *cdp.Node) chromedp.Action {
				selReviewWord := fmt.Sprintf(selReviewWordItemTpl, idx+1)
				fmt.Println("selReviewWord=>", selReviewWord)
				var text string
				return Sequence(
					chromedp.ActionFunc(func(ctx context.Context) error {
						slog.Debugf("in(%d)=>", idx)
						return nil
					}),
					chromedp.SetAttributeValue(selReviewWord, "class", "review-words", chromedp.ByQueryAll),
					ScreenshotElemAndDump(selReviewWord,
						fmt.Sprintf(`tmp/shop_%s/review_%d.png`, shopID, node.NodeID),
						tr, &text),
					chromedp.ActionFunc(func(ctx context.Context) error {
						slog.Debugf("review(%d)=>%s", idx, text)
						extracts = append(extracts, text)
						return nil
					}),
				)
			}),
			IterDoneFunc(func(ctx context.Context, matchAll bool) chromedp.Action {

				return Sequence(
					chromedp.ActionFunc(func(ctx context.Context) error {
						slog.Debugf("match all =>%v", matchAll)
						return nil
					}),
				)
			}),
			IterNodeFilterFunc(func(ctx context.Context, idx int, node *cdp.Node) bool {
				var dateString string
				if err := chromedp.Run(ctx,
					chromedp.Text("div.misc-info.clearfix > span.time", &dateString, chromedp.ByQuery, chromedp.FromNode(node.Parent)),
				); err != nil {
					slog.Errorf("review date fetch err(%d)=>%s", idx, err)
					return false
				}
				fmt.Println("dateString=>", dateString, strings.Contains(dateString, "更新于"))
				if strings.Contains(dateString, "更新于") {
					arr := strings.Split(dateString, "更新于")
					dateString = arr[1]
				}
				reviewDate, err := time.Parse("2006-01-02 15:04", dateString)
				if err != nil {
					slog.Errorf("review date parse err(%d)=>%s", idx, err)
					return false
				}
				fmt.Println("reviewDate.After(cutoffDate)=>", reviewDate.After(cutoffDate))
				return reviewDate.After(cutoffDate)
			}),
		),
	})

	// toNextPage := true
	// for toNextPage {

	// }

	return tr
}

func (tr *TaskRunner) FetchReviewsSince(shopID string, latestDays int) *TaskRunner {
	const reviewUrlTpl = "%s/shop/%s/review_all/p%d?queryType=sortType&&queryVal=latest"
	currentPage := 1

	const selReviewWords = `#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items > ul > li > div > div.review-words`
	const selReviewWordItemTpl = `#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.reviews-items > ul > li:nth-child(%d) > div > div.review-words`
	const selNextPage = `#review-list > div.review-list-container > div.review-list-main > div.reviews-wrapper > div.bottom-area.clearfix > div > a.NextPage`
	const timeLayout = `2006-01-02 15:04`
	extracts := []string{}
	now := time.Now()
	cutoffDate := now.AddDate(0, 0, -latestDays)
	isCutOff := false
	tr.tasks = append(tr.tasks, chromedp.Tasks{
		Loop(
			BreakCheckFunc(func(ctx context.Context) bool {
				return isCutOff
			}),
			chromedp.ActionFunc(func(ctx context.Context) error {
				err := chromedp.Run(ctx,
					Iter(
						selReviewWords,
						IterNodeNextFunc(func(ctx context.Context, idx int, node *cdp.Node) chromedp.Action {
							selReviewWord := fmt.Sprintf(selReviewWordItemTpl, idx+1)
							var text string
							return Sequence(
								chromedp.ActionFunc(func(ctx context.Context) error {
									slog.Debugf("in(%d)=>", idx)
									return nil
								}),
								chromedp.SetAttributeValue(selReviewWord, "class", "review-words", chromedp.ByQueryAll),
								ScreenshotElemAndDump(selReviewWord,
									fmt.Sprintf(`tmp/shop_%s/review_page_%d/review_item_%d.png`, shopID, currentPage, node.NodeID),
									tr, &text),
								chromedp.ActionFunc(func(ctx context.Context) error {
									slog.Debugf("review(%d)=>%s", idx, text)
									// text = CollapseReviewEmtpy(text)
									extracts = append(extracts, text)
									return nil
								}),
							)
						}),
						IterDoneFunc(func(ctx context.Context, matchAll bool) chromedp.Action {
							return chromedp.ActionFunc(func(ctx context.Context) error {
								slog.Debugf("match all =>%v", matchAll)
								isCutOff = !matchAll
								if matchAll {

									chromedp.Run(ctx,
										IfPresentOrElse(selNextPage, Sequence(chromedp.ActionFunc(func(ctx context.Context) error {
											slog.Debugf("next btn exist, currentPage(%d) will add 1=>", currentPage)
											currentPage++
											return nil
										})), Sequence(chromedp.ActionFunc(func(ctx context.Context) error {
											isCutOff = true
											return nil
										})),
										),
									)
								} else {
									isCutOff = true
								}
								return nil
							})
						}),
						IterNodeFilterFunc(func(ctx context.Context, idx int, node *cdp.Node) bool {
							var dateString string
							if err := chromedp.Run(ctx,
								chromedp.Text("div.misc-info.clearfix > span.time", &dateString, chromedp.ByQuery, chromedp.FromNode(node.Parent)),
							); err != nil {
								slog.Errorf("review date fetch err(%d)=>%s", idx, err)
								return false
							}
							fmt.Println("dateString=>", dateString, strings.Contains(dateString, "更新于"))
							if strings.Contains(dateString, "更新于") {
								arr := strings.Split(dateString, "更新于")
								dateString = arr[1]
							}
							reviewDate, err := time.Parse(timeLayout, dateString)
							if err != nil {
								slog.Errorf("review date parse err(%d)=>%s", idx, err)
								return false
							}
							fmt.Println("reviewDate.After(cutoffDate)=>", reviewDate.After(cutoffDate))
							return reviewDate.After(cutoffDate)
						}),
					),
					tr.wait(1),
					tr.navigateWithRefererAction(
						fmt.Sprintf(reviewUrlTpl, dpHost, shopID, currentPage+1),
						fmt.Sprintf(reviewUrlTpl, dpHost, shopID, currentPage),
					),
				)
				if err != nil {
					return err
				}
				return nil
			}),
		),
		chromedp.ActionFunc(func(ctx context.Context) error {
			tr.reviewInfo.ShopID = shopID
			tr.reviewInfo.Cnt = len(extracts)
			tr.reviewInfo.From = cutoffDate.Format(timeLayout)
			tr.reviewInfo.To = now.Format(timeLayout)
			tr.reviewInfo.ReviewItems = extracts
			return nil
		}),
	})

	return tr
}

func (tr *TaskRunner) CleanReviewInfo(cleaners ...DataCleaner) *TaskRunner {
	tr.tasks = append(tr.tasks,
		chromedp.ActionFunc(func(ctx context.Context) error {
			for i := range tr.reviewInfo.ReviewItems {
				tr.reviewInfo.ReviewItems[i] = DataClean(tr.reviewInfo.ReviewItems[i], cleaners...)
			}
			return nil
		}),
	)
	return tr
}

func (tr *TaskRunner) DumpReviewInfo() *TaskRunner {
	tr.tasks = append(tr.tasks,
		chromedp.ActionFunc(func(ctx context.Context) error {
			file := fmt.Sprintf("crawled/review/%s.json", tr.reviewInfo.ShopID)
			tr.dumpToFile(file, tr.reviewInfo)
			return nil
		}),
	)
	return tr
}

func (tr *TaskRunner) ReviewReset() *TaskRunner {
	tr.tasks = append(tr.tasks,
		chromedp.ActionFunc(func(ctx context.Context) error {
			tr.reviewInfo.ShopID = ""
			tr.reviewInfo.Cnt = 0
			tr.reviewInfo.From = ""
			tr.reviewInfo.To = ""
			tr.reviewInfo.ReviewItems = nil
			return nil
		}),
	)
	return tr.Reset()
}
